namespace GYLite
{
	export type Route = {
		/**起点索引*/stInd:number,
		/**终点索引*/endInd:number,
		/**路线*/pts:number[],
		/**起点到路线的距离*/stMinDis:number,
		/**终点到路线的距离*/endMinDis:number
	};
	export class PositionUtil
	{		
		public static _pt:egret.Point=new egret.Point;
		public constructor()
		{
		}
		/**范围限制
		 * @param value 检测值
		 * @param min 最小 默认NaN 不检测
		 * @param max 最大 默认NaN 不检测
		 * @param return 超过范围返回范围极值，否则返回当前值
		*/
		public static rangeRestrct(value:number, min:number=NaN, max:number=NaN):number
		{
			if(min == min && value < min)							
				value = min;
			else if(max == max && value > max)							
				value = max;
			return value;
		}
		/**求过点cx,cy的直线在直线l(ax,ay,bx,by)上的垂点
		 * @return 垂点坐标
		 * */
		public static verticalPoint(ax:number,ay:number,bx:number,by:number,cx:number,cy:number):egret.Point
		{
			let abx:number = bx - ax;
			let aby:number = by - ay;
			let acx:number = cx - ax;
			let acy:number = cy - ay;
			if(abx == 0 && aby == 0)return null;
			let f:number = (abx*acx+aby*acy)/(abx*abx+aby*aby);  // 注意ab必须是直线上的两个不同点
			PositionUtil._pt.x = ax + f*abx;
			PositionUtil._pt.y = ay + f*aby;
			return PositionUtil._pt;
		}
		/**判断3个点是顺时针，逆时针，还是在一条直线上面
		 * @return 小于0 逆时针 大于0 顺时针 等于0 直线 (注意2d坐标系是y轴翻转的，所以图形的顶点顺序应该跟数学计算相反)
		 * */
		public static clockwise(x1 :number,y1 :number,x2 :number,y2 :number,x3 :number,y3 :number) :number
		{
			return (x2-x1)*(y3-y2)-(y2-y1)*(x3-x2);
		}		
		/**判断路径是顺时针，逆时针，还是在一条直线上面
		 * @return 小于0 逆时针 大于0 顺时针 等于0 直线 (注意2d坐标系是y轴翻转的，所以图形的顶点顺序应该跟数学计算相反，此处表达的结果为数学坐标系上表现的顺逆时针)
		 * */
		public static clockwisePath(pathArr:Array<any>) :number
		{
			return MathUtil.calPolygonArea(pathArr, true);
		}
		/**计算路径转过的角度
		 * @return 路径转过的角度
		 * */
		public static anglePath(pathArr:Array<any>) :number
		{
			var i :number,len :number;
			var agl1 :number,agl2 :number,agl :number;
			len = pathArr.length;
			if(len < 4)
			{
				return 0;
			}
			agl = 0;
			agl1 = PositionUtil.calculateAngle(pathArr[0],pathArr[1],pathArr[2],pathArr[3]);
			if(agl1 < 0)agl1+=MathConst.DOUBLE_PI;
			agl2 = PositionUtil.calculateAngle(pathArr[pathArr.length-4],pathArr[pathArr.length - 3],pathArr[pathArr.length - 2],pathArr[pathArr.length-1]);
			if(agl2 < 0)agl2+=MathConst.DOUBLE_PI;
			agl += agl2 - agl1;
			return agl;
		}
		/**判断直线AB是否与直线CD相交*/    
		public static lineIntersectSide(ax :number,ay :number,bx :number,by :number,cx :number,cy :number,dx :number,dy :number):Boolean    
		{    
			// A(x1, y1), B(x2, y2)的直线方程为：    
			// f(x, y) =  (y - y1) * (x1 - x2) - (x - x1) * (y1 - y2) = 0    
			
			var fC :number = (cy - ay) * (ax - bx) - (cx - ax) * (ay - by);    
			var fD :number = (dy - ay) * (ax - bx) - (dx - ax) * (ay - by);    
			
			if(fC * fD > 0)    
				return false;    
			
			return true;    
		}
		/**检测图形是否相交
		 * @param shapeA [x1,y1,x2,y2……]
		 * @param shapeB [x1,y1,x2,y2……]
		*/
		public static isShapeInsert(shapeA:number[],shapeB:number[]):boolean
		{
			let i:number,len:number;
			if(shapeA == null || shapeA.length == 0 || shapeB == null || shapeB.length == 0)
				return false;
			//由于会出现两图形互相相交并没有顶点在内部的情况，所以无法用纯向量方式判断两个图形是否相交
			// len = shapeA.length;
			// for(i=0;i<len;i+=2)
			// {
			// 	if(PositionUtil.isPointInShape(shapeA[i],shapeA[i+1], shapeB))
			// 		return true;
			// }
			// if(PositionUtil.isPointInShape(shapeB[0],shapeB[1], shapeA))
			// 	return true;
			let ax1:number, ay1:number, ax2:number, ay2:number;
			let bx1:number, by1:number, bx2:number, by2:number;
			let j:number,len2:number;
			len = shapeA.length;
			for(i=0;i<len;i+=2)
			{
				ax1 = shapeA[i];
				ay1 = shapeA[i+1];
				if(i == len - 2)
				{
					ax2 = shapeA[0];
					ay2 = shapeA[1];					
				}
				else
				{
					ax2 = shapeA[i+2];
					ay2 = shapeA[i+3];
				}
				len2 = shapeB.length;
				for(j=0;j<len2;j+=2)
				{
					bx1 = shapeB[j];
					by1 = shapeB[j+1];
					if(j == len2 - 2)
					{
						bx2 = shapeB[0];
						by2 = shapeB[1];
					}
					else
					{
						bx2 = shapeB[j+2];
						by2 = shapeB[j+3];
					}
					if(PositionUtil.intersect(ax1,ay1,ax2,ay2,bx1,by1,bx2,by2))
						return true;
				}
			}
			if(PositionUtil.isPointInShape(ax1,ay1,shapeB))
				return true;
			if(PositionUtil.isPointInShape(bx1,by1,shapeA))
				return true;
			return false;
		}
		/**检测点是否在图形内*/
		public static isPointInShape(tX :number,tY :number,arr:Array<number>):boolean
		{
			let i:number,j:number;
			let len:number;	
			let oddNodes:boolean=false;
			len = arr.length;
			if(len < 6)return false;				
			j = len - 2;
			for (i=0;i < len; i+=2)
			{				
				if ((arr[i+1] > tY) != (arr[j+1] > tY) &&  (tX < (arr[j] - arr[i]) * (tY - arr[i+1]) / (arr[j+1] - arr[i+1]) + arr[i]))                
                    oddNodes = !oddNodes;
				j=i;
			}
			return oddNodes;
		}		
		/**判断两条线段是否相交*/    
		public static intersect(ax :number,ay :number,bx :number,by :number,cx :number,cy :number,dx :number,dy :number):Boolean  
		{
			//向量法求相交
			let vx1:number,vy1:number,vx2:number,vy2:number,vx3:number,vy3:number;
			let cross1:number,cross2:number,cross3:number,cross4:number;
			let mulCross1:number,mulCross2:number;
			vx1 = dx - cx;
			vy1 = dy - cy;
			vx2 = bx - dx;
			vy2 = by - dy;
			vx3 = ax - dx;
			vy3 = ay - dy;
			cross1 = MathUtil.cross(vx1,vy1,vx2,vy2);
			cross2 = MathUtil.cross(vx1,vy1,vx3,vy3);

			vx1 = bx - ax;
			vy1 = by - ay;
			vx2 = cx - bx;
			vy2 = cy - by;
			vx3 = dx - bx;
			vy3 = dy - by;
			cross3 = MathUtil.cross(vx1,vy1,vx2,vy2);
			cross4 = MathUtil.cross(vx1,vy1,vx3,vy3);
			mulCross1 = cross1 * cross2;
			mulCross2 = cross3 * cross4;
			if(mulCross1 <= 0 && mulCross2 <= 0)
				return true;			
			return false;			
		} 
		/**转换坐标
		 * @param toX 坐标X
		 * @param toY 坐标Y
		 * @param fromTarget 当前坐标的坐标系
		 * @param toTarget 目标坐标的坐标系，为null则只转到全局坐标
		 * */
		public static convertPos(toX :number,toY :number,fromTarget:egret.Sprite, toTarget:egret.Sprite=null):egret.Point
		{
			var pt:egret.Point;
			PositionUtil._pt.x = toX;
			PositionUtil._pt.y = toY;
			pt = fromTarget.localToGlobal(PositionUtil._pt.x,PositionUtil._pt.y);
			pt = toTarget?toTarget.globalToLocal(pt.x, pt.y, pt):pt;
			return pt;
		}
		/**计算两点连线的线角度（弧度，正负pi）
		 * @param aX 终点x
		 * @param aY 终点y
		 * @param aX 起点x
		 * @param aY 起点y
		 * */
		public static calculateAngle(aX :number, aY :number, bX :number, bY :number) :number
		{
			if(aX == bX)
			{
				if(aY == bY)return 0;
				return (bY > aY ? -MathConst.HALF_PI:MathConst.HALF_PI);
			}
			return Math.atan2(aY - bY,aX - bX);
		}
		/**计算两点间xy轴距离和(曼哈顿距离)*/
		public static calculateDistance3(aX :number,aY :number,bX :number,bY :number) :number
		{
			var d1 :number,d2 :number;
			d1 = bY - aY;
			d2 = bX - aX;
			if(d1 < 0)d1 = -d1;
			if(d2 < 0)d2 = -d2;
			return d1 + d2;
		}
		/**计算两点间的距离的平方*/
		public static calculateDistance2(aX :number,aY :number,bX :number,bY :number) :number
		{
			var d1 :number,d2 :number;
			d1 = bY - aY;
			d2 = bX - aX;
			return d1 * d1 + d2 * d2;
		}
		/**计算两点间的距离*/
		public static calculateDistance(aX :number,aY :number,bX :number,bY :number) :number
		{
			var d1 :number,d2 :number;
			d1 = bY - aY;
			d2 = bX - aX;
			return Math.sqrt(d1 * d1 + d2 * d2);
		}
		/**数组转成数值数组*/
		public static vectorToNumberArray(vec:Array<any>):Array<any>
		{
			var i :number,len :number;
			var arr:Array<number>=[];
			len = vec.length;
			for(i=0;i<len;++i)
			{
				arr[arr.length] = +vec[i];
			}
			return arr;
		}	
		/**数组转成整型数组*/
		public static vectorToIntArray(vec:Array<any>):Array<any>
		{
			var i :number,len :number;
			var arr:Array<number>=[];
			len = vec.length;
			for(i=0;i<len;++i)
			{
				arr[arr.length] = Math.floor(vec[i]);
			}
			return arr;
		}
		/**数组转成向下取整的整型数组*/
		public static vectorToCeilArray(vec:Array<any>):Array<any>
		{
			var i :number,len :number;
			var arr:Array<number>=[];
			len = vec.length;
			for(i=0;i<len;++i)
			{
				arr[arr.length] = Math.ceil((vec[i]));
			}
			return arr;
		}
		/**生成椭圆形描点
		 * @param rX X半径
		 * @param rY Y半径
		 * @param x 原点坐标X，默认0
		 * @param y 原点坐标X，默认0
		 * @param precision 精度（百分比）默认0.3，如果大于1，则认为是指定描点数量
		*/
		public static calRoundPoint(rX:number,rY:number,x:number=0,y:number=0, precision:number=0.25):number[]
		{
			let i:number,len:number,agl:number,step:number;
			let result:number[]=[];
			len = Math.floor(precision <= 1?Math.max(rX,rY)*Math.PI*precision*precision:precision);
			if(len < 3)
				len = 3;
			step = Math.PI*2 / len;
			agl = 0;
			for(i=0;i<len;++i,agl+=step)
			{
				result[i*2] = x + Math.cos(agl) * rX;
				result[i*2+1] = y + Math.sin(agl) * rY;
			}
			return result;
		}
		/**生成矩形描点
		 * @param rX 矩形宽度半径
		 * @param rX 矩形高度半径
		 * @param x 原点x，默认0
		 * @param y 原点y，默认0
		*/
		public static calRectPoint(rX:number,rY:number,x:number=0,y:number=0):number[]
		{
			return [x-rX,y-rY,x+rX,y-rY,x+rX,y+rY,x-rX,y+rY];
		}
		/**绕点旋转
		 * @param ox 绕x
		 * @param oy 绕y
		 * @param agl 角度
		 * demo 你可以尝试以下代码，对图像进行绕点旋转动画
		 	let img:Laya.Image = new Laya.Image;
			let offsetX:number,offsetY:number;
			offsetX = offsetY = 0;
			img.x = 500;
			img.y = 500;
			img.skin="图片路径";
			Laya.stage.addChild(img);
			CommonUtil.addStageLoop(function(t:number):void{
				let pt:Laya.Point = PositionUtil.rotationXY(26,26,img.rotation*MathConst.ROTATION_ANGLE);
				img.x -= offsetX;
				img.y -= offsetY;
				offsetX = -pt.x;
				offsetY = -pt.y;
				img.x += offsetX;
				img.y += offsetY;                        
				img.rotation += 1;
			},self);
		*/
		public static rotationXY(ox:number,oy:number,agl:number):egret.Point
		{
			this._pt.x = ox*Math.cos(agl) - oy*Math.sin(agl);
			this._pt.y = oy*Math.sin(agl) + ox*Math.cos(agl);
			return this._pt;
		}
		/**获取线段穿透的格子列表,返回数组[格子坐标y1,格子坐标x1,格子坐标y2,格子坐标x2……]，注意此处返回的是先y再x
		 * test 342,702,602,402 - 垂直角度测试
		 * test 342,702,342,402 - 垂直测试
		 * test 342,702,602,602 - 水平角度测试
		 * test 342,702,602,702 - 水平测试
		 * @param ax 起点坐标x
		 * @param ay 起点坐标y
		 * @param bx 终点坐标x
		 * @param by 终点坐标y
		 * @param areaSize 格子大小 默认32
		 * @param padding 扩展像素 默认0
		*/
		public static getAToBPosArray(ax:number,ay:number,bx:number,by:number,areaSize:number=32, padding:number=0):number[]
		{			
			let arr:number[] = [];
			let stX:number,stY:number,endX:number,endY:number;
			let i:number,len:number,j:number,len2:number;
			let p:egret.Point;
			let x:number,y:number,agl:number,sX:number,sY:number,eX:number,eY:number;
			let flagX:boolean,flagY:boolean;
			
			if(padding > 0)
			{
				let dis:number;
				let pt:egret.Point;
				dis = PositionUtil.calculateDistance(ax,ay,bx,by);
				pt = MathUtil.calLinePoint(ax,ay,bx,by,dis+padding);
				bx = pt.x;
				by = pt.y;
				pt = MathUtil.calLinePoint(bx,by,ax,ay,dis+padding);
				ax = pt.x;
				ay = pt.y;
				
			}
			// p = PositionUtil._pt;				
			sX = stX = (ax / areaSize | 0) * areaSize;				
			sY = stY = (ay / areaSize | 0) * areaSize;
			eX = endX = (bx / areaSize | 0) * areaSize;
			eY = endY = (by / areaSize | 0) * areaSize;
			agl = PositionUtil.calculateAngle(stX, stY, endX, endY);			
			
			if(agl > -MathConst.QUATER_TRIBLE_PI && agl < -MathConst.QUATER_PI || agl > MathConst.QUATER_PI && agl < MathConst.QUATER_TRIBLE_PI)
			{//偏向垂直角度，计算垂直轴相交，交点较少				
				flagX = ax < bx;
				i = flagX?stX + areaSize:-stX;
				len = flagX?-(endX + areaSize):endX;		
				for(;i+len<=0;i+=areaSize)	//X轴每列判断
				{		
					x = flagX?i:-i;				
					p = MathUtil.calCrossPoint(ax,ay,bx,by,x,ay,x,by);
					if(sY < eY)
						flagY = p == null || p.y < eY && p.y < sY || p.y > eY && p.y > sY;
					else
						flagY = p == null || p.y < eY && p.y < sY + areaSize || p.y > eY && p.y > sY + areaSize;
					endY = ((flagY?eY:p.y) / areaSize | 0) * areaSize;
					flagY = stY < endY;
					j = flagY?(stY - padding):-(stY + padding);
					len2 = flagY?-(endY + padding):(endY - padding);
					for(;j+len2<=0;j+=areaSize)//每行判断
					{
						y = flagY?j:-j;
						arr.push(y, flagX?x-areaSize:x);
					}
					stY = endY;				
				}				
			}
			else
			{//偏向水平角度，计算垂直轴相交，交点较少
				flagY = ay < by;
				i = flagY?stY + areaSize:-stY;
				len = flagY?-(endY + areaSize):endY;		
				for(;i+len<=0;i+=areaSize)	//Y轴每行判断
				{		
					y = flagY?i:-i;				
					p = MathUtil.calCrossPoint(ax,ay,bx,by,ax,y,bx,y);
					if(sX < eX)
						flagX = p == null || p.x < eX && p.x < sX || p.x > eX && p.x > sX;
					else
						flagX = p == null || p.x < eX && p.x < sX + areaSize || p.x > eX && p.x > sX + areaSize;
					endX = ((flagX?eX:p.x) / areaSize | 0) * areaSize;
					flagX = stX < endX;
					j = flagX?(stX - padding):-(stX + padding);
					len2 = flagX?-(endX + padding):(endX - padding);
					for(;j+len2<=0;j+=areaSize)//每列判断
					{
						x = flagX?j:-j;
						arr.push(flagY?y-areaSize:y, x);
					}
					stX = endX;				
				}
			}
			// arr.push(eY, eX);
			return arr;
		}
		/**根据图形顶点区域获取网格定点数组
		 * @param arr 图形顶点数组[x0,y0,x1,y1……]
		 * @param paddingX 间隔X
		 * @param paddingY 间隔Y
		 * @param staggerd 是否交错布局，默认false 二维格子布局，交错则每行间隔半个，每列错位半格
		 * 
		*/
		public static getGridPosByShape(arr:number[],paddingX:number=200,paddingY:number=120,staggerd:boolean=false)
		{			
			let minX:number,minY:number,maxX:number,maxY:number;
			let i:number,len:number,j:number,len2:number;
			let centerX:number,centerY:number,startX:number,startY:number;			
			let points:number[];
			minY = minX = Number.MAX_VALUE;
			maxX = maxY = Number.MIN_VALUE;
			points = [];
			len = arr.length;
			if(len > 0)
			{				
				centerX = paddingX >> 1;
				centerY = paddingY >> 1;
				len = arr.length;
				for(i=0;i<len;i+=2)
				{
					minX = Math.min(arr[i],minX);
					minY = Math.min(arr[i+1],minY);
					maxX = Math.max(arr[i],maxX);
					maxY = Math.max(arr[i+1],maxY);
				}										
				len = maxX + centerX;
				len2 = maxY + centerY;
				startX = minX + centerX;
				startY = minY + centerY;
				for(i=startX;i<=len;i+=paddingX)
				{
					for(j=startY;j<=len2;j+=paddingY)
					{
						if(PositionUtil.isPointInShape(i,j,arr))
						{
							points.push(i,j);								
						}					
						if(staggerd)
						{
							if(i == startX)
							{
								if(PositionUtil.isPointInShape(i - centerX,j - centerY,arr))
									points.push(i - centerX,j - centerY);									
							}								
							if(PositionUtil.isPointInShape(i + centerX,j + centerY,arr))
								points.push(i + centerX,j + centerY);
						}		
					}
				}				
			}
			return points;
		}
		/**根据起点到终点，在指定的路线pts中，找到一段最短的途径路线
		 * @param stX 起点x
		 * @param stY 起点y
		 * @param endX 终点x
		 * @param endY 终点y
		 * @param pts 路线
		 * **/
		public static getBestRoute(stX:number,stY:number,endX:number,endY:number,pts:number[]):Route
		{
			let i:number,len:number;
			let x:number,y:number, x2:number, y2:number,stInd:number, endInd:number,stMinDis:number,endMinDis:number;
			let dis:number,dot:number;
			stMinDis = Number.MAX_VALUE;
			endMinDis = Number.MAX_VALUE;
			len = pts.length;
			for(i=0;i<len;i+=2)
			{
				x = pts[i];
				y = pts[i+1];		
				
				dis = PositionUtil.calculateDistance2(x,y,stX,stY);
				if(dis < stMinDis)
				{
					if(i == len - 2)
					{
						stMinDis = dis;												
						stInd = i;
					}
					else
					{
						x2 = pts[i + 2];
						y2 = pts[i + 3];
						dot = MathUtil.dot(x - stX, y - stY, x2 - x, y2 - y);
						if(dot > 0)//只要（起点-途径点）*（途径点-下一个途径点）是锐钝角关系的途径点
						{
							stMinDis = dis;												
							stInd = i;
						}			
					}			
				}	
			
				dis = PositionUtil.calculateDistance2(x,y,endX,endY);
				if(dis < endMinDis)
				{
					if(i == 0)
					{
						endMinDis = dis;						
						endInd = i;
					}
					else
					{
						x2 = pts[i - 2];
						y2 = pts[i - 1];
						dot = MathUtil.dot(x - endX,y - endY,x - x2,y - y2);
						if(dot < 0)//只要（终点-途径点）*（途径点-下一个途径点）是钝角关系的途径点
						{
							endMinDis = dis;						
							endInd = i;
						}
					}					
				}
				
			}
			if(pts.length < 4)
				return null;
			return {stMinDis:stMinDis,endMinDis:endMinDis,stInd:stInd,endInd:endInd,pts:pts};
		}
		/**从起点索引stInd到终点索引截取一段数组的元素，stInd大于endInd则会自动反向顺序截取到新数组中
		 * @param arr 数组
		 * @param stInd 起始索引
		 * @param endInd 结束索引
		 * @param step 数组多少个元素作为一组，例如坐标[x1,y1,x2,y2……]则step为2，默认1
		*/
		public sliceArray(arr:any[], stInd:number,endInd:number,step:number=1):any[]
		{
			let i:number,len:number,j:number,len2:number;
			let result:any[]=[];
			len = arr.length;
			i = stInd < endInd?i:-i;
			len = stInd < endInd?-len:len;			
			for(i=0;i+len<0;i+=step)
			{				
				if(step == 1)
					result.push(result[i]);
				else
				{
					len2 = step;
					for(j=0;j<len2;++j)					
						result.push(result[i+j]);
				}				
			}
			return result;
		}
	}
}